package charts; 

import flash.events.Event;
import flash.events.MouseEvent;
import charts.series.Element;
import string.Utils;
import flash.display.BlendMode;
import flash.display.Sprite;

import charts.series.dots.DefaultDotProperties;
import charts.series.dots.DotFactory;

import charts.Structs.StyleStruct;

class Line extends Base<Element> {

	// JSON style:
	var style:Style;
	var props:Properties;

	var key:String;
	var font_size:Float;
	var values:Array<Dynamic>; // TODO - figure out the actual type instead of Dynamic
	
	public function new( json:Dynamic ) {
		super();
		style = {
			values: 		[],
			width:			2,
			colour: 		'#3030d0',
			text: 			'',		// <-- default not display a key
			font_size: 	12,
			tip:			'#val#',
			line_style:	new LineStyle( json['line-style'] ),
			loop:			false,
			axis:			'left'
			// HACK: fix this (remove the merge below)
		};
		
		// hack: keep this incase the merge kills it, we'll
		// remove the merge later (and this hack)
		var js:Dynamic = json['dot-style'];
		
		Object_helper.merge_2( json, style );
		
		props = new DefaultDotProperties( js, style.colour, style.axis);
		
		style.colour = string.Utils.get_colour( style.colour );
		
		key		= style.text;
		font_size	= style.font_size;
		
		values = style.values;
		add_values();

		//
		// this allows the dots to erase part of the line
		//
		blendMode = BlendMode.LAYER;
		
	}
	
	//
	// called from the BaseLine object
	//
	override function get_element( index:Float, value:Dynamic ): Element {

		if ( Std.is( value, Float) )
			value = { value:value };
			
		var prop:Properties = new Properties( value, props);
			
		// Minor hack, replace all #key# with this key text,
		// we do this *after* the merge.
		//prop.set( 'tip', prop.get('tip').replace('#key#', key) );
		prop.set( 'tip', StringTools.replace(prop.get('tip'),'#key#', key) );
			
		return DotFactory.make( index, prop );
	}
	
	
	// Draw lines...
//	public override function resize( sc:ScreenCoordsBase ): Void {
	public function resize( sc:ScreenCoordsBase ): Void {
		x = y = 0;

		graphics.clear();
		graphics.lineStyle( style.width, style.colour );
		
		if( style['line-style'].style != 'solid' )
			dash_line(sc);
		else
			solid_line(sc);
	
	}
	
	public function solid_line( sc:ScreenCoordsBase ): Void {
		
		var first:Bool = true;
		var i:Float;
		var spr:Sprite;
		var x:Float;
		var y:Float;
		
		for ( i in 0...numChildren) {

			spr = cast( getChildAt(i), Sprite);
			
			//
			// filter out the line masks
			//
			if( Std.is( spr, Element) )
			{
				var e:Element = cast( spr, Element);
				
				// tell the Point where it is on the screen
				// we will use this info to place the tooltip
				e.resize( sc );
				if( first )
				{
					graphics.moveTo(e.x, e.y);
					x = e.x;
					y = e.y;
					first = false;
				}
				else
					graphics.lineTo(e.x, e.y);
			}
		}
		
		if ( style.loop ) {
			// close the line loop (radar charts)
			graphics.lineTo(x, y);
		}
	}
	
	// Dashed lines by Arseni
	public function dash_line( sc:ScreenCoordsBase ): Void {
		
		var first:Bool = true;
		
		var prev_x:Int = 0;
		var prev_y:Int = 0;
		var on_len_left:Int = 0;
		var off_len_left:Int = 0;
		var on_len:Int = style['line-style'].on; //Stroke Length
		var off_len:Int = style['line-style'].off; //Space Length
		var now_on:Bool = true;
		
		for ( i in 0...numChildren) {				
			var spr:Sprite = cast( getChildAt(i), Sprite);				
			//
			// filter out the line masks
			//
			if( Std.is( spr, Element) )
			{
				var e:Element = cast( spr, Element);
				
				// tell the Point where it is on the screen
				// we will use this info to place the tooltip
				e.resize( sc );
				if( first )
				{
					graphics.moveTo(e.x, e.y);
					on_len_left = on_len;
					off_len_left = off_len;
					now_on = true;
					first = false;
					prev_x = e.x;
					prev_y = e.y;
					var x_tmp_1:Int = prev_x;
					var x_tmp_2:Float;
					var y_tmp_1:Int = prev_y;
					var y_tmp_2:Float;						
				}
				else {
					var part_len:Int = Math.sqrt((e.x - prev_x) * (e.x - prev_x) + (e.y - prev_y) * (e.y - prev_y) );
					var sinus:Int = ((e.y - prev_y) / part_len); 
					var cosinus:Int = ((e.x - prev_x) / part_len); 
					var part_len_left:Int = part_len;
					var inside_part:Bool = true;
						
					while (inside_part) {
						//Draw Lines And spaces one by one in loop
						if ( now_on ) {
							//Draw line
							//If whole stroke fits
							if (  on_len_left < part_len_left ) {
								//Fits - draw whole stroke
								x_tmp_2 = x_tmp_1 + on_len_left * cosinus;
								y_tmp_2 = y_tmp_1 + on_len_left * sinus;
								x_tmp_1 = x_tmp_2;
								y_tmp_1 = y_tmp_2;
								part_len_left = part_len_left - on_len_left;
								now_on = false;
								off_len_left = off_len;															
							} else {
								//Does not fit - draw part of the stroke
								x_tmp_2 = e.x;
								y_tmp_2 = e.y;
								x_tmp_1 = x_tmp_2;
								y_tmp_1 = y_tmp_2;
								on_len_left = on_len_left - part_len_left;
								inside_part = false;									
							}
							graphics.lineTo(x_tmp_2, y_tmp_2);								
						} else {
							//Draw space
							//If whole space fits
							if (  off_len_left < part_len_left ) {
								//Fits - draw whole space
								x_tmp_2 = x_tmp_1 + off_len_left * cosinus;
								y_tmp_2 = y_tmp_1 + off_len_left * sinus;
								x_tmp_1 = x_tmp_2;
								y_tmp_1 = y_tmp_2;
								part_len_left = part_len_left - off_len_left;								
								now_on = true;
								on_len_left = on_len;
							} else {
								//Does not fit - draw part of the space
								x_tmp_2 = e.x;									
								y_tmp_2 = e.y;									
								x_tmp_1 = x_tmp_2;
								y_tmp_1 = y_tmp_2;
								off_len_left = off_len_left - part_len_left;
								inside_part = false;																		
							}
							graphics.moveTo(x_tmp_2, y_tmp_2);								
						}
					}
				}
				prev_x = e.x;
				prev_y = e.y;
			}
		}
	}
	
//	public override function get_colour(): Float {
	public function get_colour(): Float {
		return style.colour;
	}
}
